home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / rc-1.000 / rc-1 / rc-1.5-linux / input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-07  |  7.2 KB  |  363 lines

  1. /* input.c: i/o routines for files and pseudo-files (strings) */
  2.  
  3. #include <errno.h>
  4. #include <setjmp.h>
  5. #include "rc.h"
  6. #include "jbwrap.h"
  7.  
  8. /*
  9.    NB: character unget is supported for up to two characters, but NOT
  10.    in the case of EOF. Since EOF does not fit in a char, it is easiest
  11.    to support only one unget of EOF.
  12. */
  13.  
  14. typedef struct Input {
  15.     inputtype t;
  16.     char *ibuf;
  17.     int fd, index, read, lineno, last;
  18.     bool saved, eofread;
  19. } Input;
  20.  
  21. #define BUFSIZE ((SIZE_T) 256)
  22.  
  23. #ifdef READLINE
  24. extern char *readline(char *);
  25. extern void add_history(char *);
  26. static char *rlinebuf;
  27. #endif
  28.  
  29. char *prompt, *prompt2;
  30. bool rcrc;
  31.  
  32. static int dead(void);
  33. static int fdgchar(void);
  34. static int stringgchar(void);
  35. static void history(void);
  36. static void ugdead(int);
  37. static void pushcommon(void);
  38.  
  39. static char *inbuf;
  40. static SIZE_T istacksize, chars_out, chars_in;
  41. static bool eofread = FALSE, save_lineno = TRUE;
  42. static Input *istack, *itop;
  43.  
  44. static int (*realgchar)(void);
  45. static void (*realugchar)(int);
  46.  
  47. int last;
  48.  
  49. extern int gchar() {
  50.     int c;
  51.  
  52.     if (eofread) {
  53.         eofread = FALSE;
  54.         return last = EOF;
  55.     }
  56.  
  57.     while ((c = (*realgchar)()) == '\0')
  58.         pr_error("warning: null character ignored");
  59.  
  60.     return c;
  61. }
  62.  
  63. extern void ugchar(int c) {
  64.     (*realugchar)(c);
  65. }
  66.  
  67. static int dead() {
  68.     return last = EOF;
  69. }
  70.  
  71. static void ugdead(int c) {
  72.     return;
  73. }
  74.  
  75. static void ugalive(int c) {
  76.     if (c == EOF)
  77.         eofread = TRUE;
  78.     else
  79.         inbuf[--chars_out] = c;
  80. }
  81.  
  82. /* get the next character from a string. */
  83.  
  84. static int stringgchar() {
  85.     return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
  86. }
  87.  
  88. /* signal-safe readline wrapper */
  89.  
  90. #ifdef READLINE
  91. #ifndef SVSIGS
  92. static char *rc_readline(char *prompt) {
  93.     char *r;
  94.     interrupt_happened = FALSE;
  95.     if (!setjmp(slowbuf.j)) {
  96.         slow = TRUE;
  97.         if (!interrupt_happened)
  98.             r = readline(prompt);
  99.         else
  100.             r = NULL;
  101.     } else
  102.         r = NULL;
  103.     slow = FALSE;
  104.     if (r == NULL)
  105.         errno = EINTR;
  106.     sigchk();
  107.     return r;
  108. }
  109. #else
  110. #define rc_readline readline
  111. #endif /* SVSIGS */
  112. #endif /* READLINE */
  113.  
  114. /*
  115.    read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor
  116.    the buffer to look like a regular fdgchar buffer.
  117. */
  118.  
  119. static int fdgchar() {
  120.     if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */
  121.         while (1) {
  122. #ifdef READLINE
  123.             if (interactive && istack->fd == 0) {
  124.                 rlinebuf = readline(prompt);
  125.                 if (rlinebuf == NULL) {
  126.                     chars_in = 0;
  127.                 } else {
  128.                     if (*rlinebuf != '\0')
  129.                         add_history(rlinebuf);
  130.                     chars_in = strlen(rlinebuf) + 1;
  131.                     efree(inbuf);
  132.                     inbuf = ealloc(chars_in + 3);
  133.                     strcpy(inbuf+2, rlinebuf);
  134.                     strcat(inbuf+2, "\n");
  135.                     efree(rlinebuf);
  136.                 }
  137.             } else
  138. #endif
  139.                 {
  140.                 long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE);
  141.                 sigchk();
  142.                 if (r < 0) {
  143.                     uerror("read");
  144.                     rc_exit(1);
  145.                 }
  146.                 chars_in = (SIZE_T) r;
  147.             }
  148.             break;
  149.         }
  150.         if (chars_in == 0)
  151.             return last = EOF;
  152.         chars_out = 2;
  153.         if (dashvee)
  154.             writeall(2, inbuf + 2, chars_in);
  155.         history();
  156.     }
  157.     return last = inbuf[chars_out++];
  158. }
  159.  
  160. /* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
  161.  
  162. extern void initinput() {
  163.     istack = itop = ealloc(istacksize = 256 * sizeof (Input));
  164.     istack->t = iFd;
  165.     istack->fd = -1;
  166.     realugchar = ugalive;
  167. }
  168.  
  169. /* push an input source onto the stack. set up a new input buffer, and set gchar() */
  170.  
  171. static void pushcommon() {
  172.     SIZE_T idiff;
  173.     istack->index = chars_out;
  174.     istack->read = chars_in;
  175.     istack->ibuf = inbuf;
  176.     istack->lineno = lineno;
  177.     istack->saved = save_lineno;
  178.     istack->last = last;
  179.     istack->eofread = eofread;
  180.     istack++;
  181.     idiff = istack - itop;
  182.     if (idiff >= istacksize / sizeof (Input)) {
  183.         itop = erealloc(itop, istacksize *= 2);
  184.         istack = itop + idiff;
  185.     }
  186.     realugchar = ugalive;
  187.     chars_out = 2;
  188.     chars_in = 0;
  189. }
  190.  
  191. extern void pushfd(int fd) {
  192.     pushcommon();
  193.     istack->t = iFd;
  194.     save_lineno = TRUE;
  195.     istack->fd = fd;
  196.     realgchar = fdgchar;
  197.     inbuf = ealloc(BUFSIZE + 2);
  198.     lineno = 1;
  199. }
  200.  
  201. extern void pushstring(char **a, bool save) {
  202.     pushcommon();
  203.     istack->t = iString;
  204.     save_lineno = save;
  205.     inbuf = mprint("..%A", a);
  206.     realgchar = stringgchar;
  207.     if (save_lineno)
  208.         lineno = 1;
  209.     else
  210.         --lineno;
  211. }
  212.  
  213. /* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */
  214.  
  215. extern void popinput() {
  216.     if (istack->t == iFd)
  217.         close(istack->fd);
  218.     efree(inbuf);
  219.     --istack;
  220.     realgchar = (istack->t == iString ? stringgchar : fdgchar);
  221.     if (istack->t == iFd && istack->fd == -1) { /* top of input stack */
  222.         realgchar = dead;
  223.         realugchar = ugdead;
  224.     }
  225.     last = istack->last;
  226.     eofread = istack->eofread;
  227.     inbuf = istack->ibuf;
  228.     chars_out = istack->index;
  229.     chars_in = istack->read;
  230.     if (save_lineno)
  231.         lineno = istack->lineno;
  232.     else
  233.         lineno++;
  234.     save_lineno = istack->saved;
  235. }
  236.  
  237. /* flush input characters upto newline. Used by scanerror() */
  238.  
  239. extern void flushu() {
  240.     int c;
  241.     if (last == '\n' || last == EOF)
  242.         return;
  243.     while ((c = gchar()) != '\n' && c != EOF)
  244.         ; /* skip to newline */
  245.     if (c == EOF)
  246.         ugchar(c);
  247. }
  248.  
  249. /* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
  250.  
  251. extern Node *doit(bool execit) {
  252.     bool eof;
  253.     Jbwrap j;
  254.     Estack e1, e2;
  255.     Edata jerror;
  256.     if (dashen)
  257.         execit = FALSE;
  258.     setjmp(j.j);
  259.     jerror.jb = &j;
  260.     except(eError, jerror, &e1);
  261.     for (eof = FALSE; !eof;) {
  262.         Edata block;
  263.         block.b = newblock();
  264.         except(eArena, block, &e2);
  265.         sigchk();
  266.         if (dashell) {
  267.             char *fname[3];
  268.             fname[1] = concat(varlookup("home"), word("/.rcrc", NULL))->w;
  269.             fname[2] = NULL;
  270.             rcrc = TRUE;
  271.             dashell = FALSE;
  272.             b_dot(fname);
  273.         }
  274.         if (interactive) {
  275.             List *s;
  276.             if (!dashen && fnlookup("prompt") != NULL) {
  277.                 static char *arglist[] = { "prompt", NULL };
  278.                 funcall(arglist);
  279.             }
  280.             if ((s = varlookup("prompt")) != NULL) {
  281. #ifdef READLINE
  282.                 prompt = s->w;
  283. #else
  284.                 fprint(2, "%s", s->w);
  285. #endif
  286.                 prompt2 = (s->n == NULL ? "" : s->n->w);
  287.             }
  288.         }
  289.         inityy();
  290.         if (yyparse() == 1 && execit)
  291.             rc_raise(eError);
  292.         eof = (last == EOF); /* "last" can be clobbered during a walk() */
  293.         if (parsetree != NULL) {
  294.             if (execit)
  295.                 walk(parsetree, TRUE);
  296.             else if (dashex && dashen)
  297.                 fprint(2, "%T\n", parsetree);
  298.         }
  299.         unexcept(); /* eArena */
  300.     }
  301.     popinput();
  302.     unexcept(); /* eError */
  303.     return parsetree;
  304. }
  305.  
  306. /* parse a function imported from the environment */
  307.  
  308. extern Node *parseline(char *extdef) {
  309.     int i = interactive;
  310.     char *in[2];
  311.     Node *fun;
  312.     in[0] = extdef;
  313.     in[1] = NULL;
  314.     interactive = FALSE;
  315.     pushstring(in, TRUE);
  316.     fun = doit(FALSE);
  317.     interactive = i;
  318.     return fun;
  319. }
  320.  
  321. /* write last command out to a file if interactive && $history is set */
  322.  
  323. static void history() {
  324.     List *hist;
  325.     SIZE_T a;
  326.  
  327.     if (!interactive || (hist = varlookup("history")) == NULL)
  328.         return;
  329.  
  330.     for (a = 0; a < chars_in; a++) {
  331.         char c = inbuf[a+2];
  332.  
  333.         /* skip empty lines and comments */
  334.         if (c == '#' || c == '\n')
  335.             break;
  336.  
  337.         /* line matches [ \t]*[^#\n] so it's ok to write out */
  338.         if (c != ' ' && c != '\t') {
  339.             char *name = hist->w;
  340.             int fd = rc_open(name, rAppend);
  341.             if (fd < 0) {
  342.                 uerror(name);
  343.                 varrm(name, TRUE);
  344.             } else {
  345.                 writeall(fd, inbuf + 2, chars_in);
  346.                 close(fd);
  347.             }
  348.             break;
  349.         }
  350.     }
  351. }
  352.  
  353. /* close file descriptors after a fork() */
  354.  
  355. extern void closefds() {
  356.     Input *i;
  357.     for (i = istack; i != itop; --i)    /* close open scripts */
  358.         if (i->t == iFd && i->fd > 2) {
  359.             close(i->fd);
  360.             i->fd = -1;
  361.         }
  362. }
  363.